

package VisAVisTab;

// Imports
///////////////
import com.hp.hpl.jena.ontology.*;
import com.hp.hpl.jena.rdf.model.*;
import java.util.*;
import javax.swing.tree.*;

/**
 * This class shows a tree representation of the class hierarchy of the ontology opened
 */
public class ClassHierarchy{
    
    DefaultMutableTreeNode rootNode;
    public DefaultTreeModel treeModel ;
    OntModel model;
    
    
    public ClassHierarchy(){
    }
    
    
    /** Show the sub-class hierarchy encoded by the given model */
    public void showHierarchy(OntModel m ) {
        model=m;
        
        Iterator objit=m.listObjectProperties();
        Iterator datait=m.listDatatypeProperties();
        Iterator propit=m.listOntProperties();
        
        //find subclasses for node Thing
        Iterator i =rootClasses(m);
        Vector vsub=new Vector();
        while (i.hasNext()){
            vsub.addElement((OntClass)i.next());
        }
        
        //find (object, datatype(and OntProperties)) properties for node Thing
        Vector vprop=new Vector();
        while (objit.hasNext()){
            OntProperty currentProperty=(OntProperty)objit.next();
            Iterator objit2=currentProperty.listDomain();
            boolean root=false;
            
            while (objit2.hasNext()) {
                root= (objit2.next().toString().equalsIgnoreCase("THING"));
                if (root) break;
            }
            boolean noDomain=false;
            noDomain= (currentProperty.getCardinality(m.getProfile().DOMAIN() ) == 0);
            if (root||noDomain) vprop.addElement(currentProperty);
        }
        while (datait.hasNext()){
            OntProperty currentProperty=(OntProperty)datait.next();
            Iterator datait2=currentProperty.listDomain();
            boolean root=false;
            
            while (datait2.hasNext()) {
                root= (datait2.next().toString().equalsIgnoreCase("THING"));
                if (root) break;
            }
            boolean noDomain=false;
            noDomain= (currentProperty.getCardinality(m.getProfile().DOMAIN() ) == 0);
            if (root||noDomain) vprop.addElement(currentProperty);
        }
        while (propit.hasNext()){
            OntProperty currentProperty=(OntProperty)propit.next();
            Iterator propit2=currentProperty.listDomain();
            boolean root=false;
            
            while (propit2.hasNext()) {
                root= (propit2.next().toString().equalsIgnoreCase("THING"));
                if (root) break;
            }
            boolean noDomain=false;
            noDomain= (currentProperty.getCardinality(m.getProfile().DOMAIN() ) == 0);
            if (root||noDomain) vprop.addElement(currentProperty);
        }
        
        
        //create a tree node for class "OWL:THING" whether it already exists in the ontology or not
        NodeInfo rootInfo;
        Resource thing=m.getProfile().THING();
        if (thing!=null){
            ClassInfo clsInfo=new ClassInfo(thing.getURI(),ClassInfo.THING,vsub,null,null,vprop,null);
            rootInfo=new NodeInfo(NodeInfo.CLASS,thing.getURI(),clsInfo,null);
            rootNode = new DefaultMutableTreeNode(rootInfo);
            treeModel= new DefaultTreeModel(rootNode) ;
        } else {
            System.out.println("No thing resource mentioned.Adding root node...");
            ClassInfo clsInfo=new ClassInfo("OWL:THING",ClassInfo.THING,vsub,null,null,vprop,null);
            rootInfo=new NodeInfo(NodeInfo.CLASS,"OWL:THING",clsInfo,null);
            rootNode = new DefaultMutableTreeNode(rootInfo);
            treeModel= new DefaultTreeModel(rootNode) ;
        }
        
        
        //find the Properties that do not have a domain and add them in a vector,in order to know that they have Thing as their domain
        
        Vector propOnTop=new Vector();
        
        Iterator genit=vprop.iterator();
        while (genit.hasNext()){
            OntProperty currentProperty=(OntProperty)genit.next();
            boolean noDomain=false;
            noDomain= (currentProperty.getCardinality(m.getProfile().DOMAIN() ) == 0);
            if (noDomain) propOnTop.addElement(currentProperty);
        }
        
        //recurse down to the sub-classes,calling method showClass for the classes that are direct sub-classes of class Thing
        for (i = rootClasses( m );  i.hasNext();  ) {
            showClass((OntClass) i.next(),rootNode, new ArrayList(),propOnTop );
        }
        
    }
    
    
    
    /** Present a class, then recurse down to the sub-classes.
     *  Use occurs check to prevent getting stuck in a loop
     *
     */
    protected void showClass(OntClass cls, DefaultMutableTreeNode parentNode, List occurs,Vector propOnTop ) {
        
        
        /** find the direct sub-classes,super-classes,disjoint classes,declared properties
         * and restrictions related to this class,in order to create and fill a new structure ClassInfo
         * which will be added to the tree
         */
        Iterator isub=findSubclasses(cls);
        Vector subClasses=new Vector();
        while (isub.hasNext())  subClasses.addElement((OntClass)isub.next());
        
        
        
        Vector superClasses=new Vector();
        Iterator isuper=findSuperclasses(cls);
        while (isuper.hasNext()) superClasses.addElement((OntClass)isuper.next());
        
        
        if (superClasses.size()!=1){
            Iterator iroot =rootClasses(model);
            while (iroot.hasNext()){
                OntClass cur=(OntClass)iroot.next();
                if (cur.getURI().equals(cls.getURI())){
                    superClasses.addElement(model.getProfile().THING());
                }
            }
        }
        
        Iterator idis=cls.listDisjointWith();
        Vector disjoint=new Vector();
        while (idis.hasNext()) disjoint.addElement((OntClass)idis.next());
        
        
        Iterator iprop=cls.listDeclaredProperties(true);
        Vector properties=new Vector();
        while (iprop.hasNext()){
            OntProperty current = (OntProperty)iprop.next();
            if (!propOnTop.contains(current)) properties.addElement(current);
        }
        
        Iterator ires = findRestrictions(cls);
        Vector restrictions = new Vector();
        while (ires.hasNext()) restrictions.addElement((Restriction)ires.next());
        
        
        
        ClassInfo nodeInfo=new ClassInfo(cls.getURI(),ClassInfo.CLASS,subClasses,superClasses,disjoint,properties,restrictions);
        NodeInfo myInfo=new NodeInfo(NodeInfo.CLASS,cls.getURI(),nodeInfo,null);
        DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(myInfo);
        treeModel.insertNodeInto(childNode, parentNode, parentNode.getChildCount());
        
        
        
        
        
        // recurse to the next level down
        if (cls.canAs( OntClass.class )  &&  !occurs.contains( cls )) {
            for (Iterator i = findSubclasses( cls );  i.hasNext(); ) {
                OntClass sub = (OntClass) i.next();
                
                // we push this expression on the occurs list before we recurse
                occurs.add( cls );
                showClass(sub,childNode, occurs,propOnTop );
                occurs.remove( cls );
            }
        }
    }
    
    
    
    /**
     * Answer an iterator over the classes we will use as the roots of the depicted
     * hierarchy.  We use named classes that either have Thing as a direct super-class,
     * or which have no declared super-classes.
     * @param m A model
     * @return An iterator over the named class hierarchy roots in m
     */
    protected Iterator rootClasses( OntModel m ) {
        List roots = new ArrayList();
        
        for (Iterator i = m.listClasses();  i.hasNext(); ) {
            OntClass c = (OntClass) i.next();
            
            if (c.isAnon()) {
                continue;
            }
            
            Iterator isuper=findSuperclasses(c);
            if (!isuper.hasNext()||(c.hasSuperClass( m.getProfile().THING(), true ) )) roots.add(c);
            
        }
        
        return roots.iterator();
    }
    
    /**Answer an iterator over the sub-classes of the given class
     *
     */
    public Iterator findSubclasses(OntClass cls){
        
        
        /*find the sub-classes that are defined inside an <equivalentClass> tag,which are not returned by
         * the listSubclasses() method
         *They usually represent necessary and sufficient conditions for an individual to belong to a certain class
         */
        Vector v=new Vector();
        for (Iterator i = model.listNamedClasses();  i.hasNext(); ) {
            OntClass c=(OntClass)i.next();
            Iterator i2=c.listEquivalentClasses();
            while (i2.hasNext()){
                OntClass current= (OntClass)i2.next();
                if (current.isIntersectionClass()){
                    IntersectionClass inter=current.asIntersectionClass();
                    Iterator i3=inter.listOperands();
                    while (i3.hasNext()){
                        OntClass oper=(OntClass)i3.next();
                        if (!oper.isAnon()&&(oper.getLocalName().equals(cls.getLocalName()))){
                            v.addElement(c);
                        }
                    }
                }
                
            }
        }
        
        //find only the sub-classes which are declared through a <subclass-of> tag
        Iterator i3= cls.listSubClasses();
        while (i3.hasNext()){
            OntClass current=(OntClass)i3.next();
            if (!current.isAnon()){
                v.addElement(current);
            }
            
        }
        return v.iterator();
    }
    
    /**Answer an iterator over the super-classes of the given class
     *
     */
    
    public Iterator findSuperclasses(OntClass cls){
        
        /*find the super-classes that are defined inside an <equivalentClass> tag,which are not returned by
         * the listSuperclasses() method
         *They usually represent necessary and sufficient conditions for an individual to belong to a certain class
         */
        Vector v=new Vector();
        Iterator i=cls.listEquivalentClasses();
        while (i.hasNext()){
            OntClass current= (OntClass)i.next();
            if (current.isIntersectionClass()){
                IntersectionClass inter=current.asIntersectionClass();
                Iterator i2=inter.listOperands();
                while (i2.hasNext()){
                    OntClass oper=(OntClass)i2.next();
                    if (!oper.isAnon()){
                        v.addElement(oper);
                    }
                }
            }
            
        }
        
        //find only the super-classes which are declared through a <subclassOf> tag
        Iterator i3= cls.listSuperClasses();
        while (i3.hasNext()){
            OntClass current=(OntClass)i3.next();
            if (!current.isAnon()){
                v.addElement(current);
            }
            
        }
        return v.iterator();
    }
    
    /**Answer an iterator over the restrictions related to the definition of the given class
     *
     */
    public Iterator findRestrictions(OntClass cls){
        
        //find restrictions in <equivalentClass> tag
        Vector v=new Vector();
        Iterator i=cls.listEquivalentClasses();
        while (i.hasNext()){
            OntClass current= (OntClass)i.next();
            if (current.isIntersectionClass()){
                IntersectionClass inter=current.asIntersectionClass();
                Iterator i2=inter.listOperands();
                while (i2.hasNext()){
                    OntClass oper=(OntClass)i2.next();
                    if (oper.isRestriction())  v.addElement(oper.asRestriction());
                }
            }
            
        }
        
        //find restrictions in <subclassOf> tags
        i=cls.listSuperClasses(true);
        while (i.hasNext()){
            OntClass current = (OntClass)i.next();
            if (current.isRestriction()) v.addElement(current.asRestriction());
        }
        
        return v.iterator();
    }
    
}


/*A class that describes a node of a JTree
 */
class NodeInfo extends Object{
    
    public NodeInfo(int type,String name,ClassInfo classInfo,PropertyInfo propertyInfo){
        
        this.type=type;             //can be either Class or Property
        this.name=name;             //the name of the node
        this.classInfo=classInfo;
        this.propertyInfo=propertyInfo;
    }
    
    public String toString() {
        return name.substring(name.indexOf('#')+1);
    }
    
    public int type;
    public ClassInfo classInfo;
    public PropertyInfo propertyInfo;
    public String name;
    
    public static final int PROPERTY = 102;
    public static final int CLASS = 1;
    public static final int OTHER = -1;
}


/*A class that contains all the information for a certain class
 **/
class ClassInfo extends Object {
    
    public ClassInfo(String text, int type, Vector vsub,Vector vsup,Vector vdis,Vector vprop,Vector vres) {
        name = text;
        this.type = type; //can be either Class or Thing
        subClasses=vsub;  //sub-Classes
        superClasses=vsup; //super-Classes
        disjoint=vdis;     //disjoint Classes
        properties=vprop;  //declared Properties
        restrictions = vres; //related Restrictions
    }
    
    
    public String toString() {
        return name;
    }
    
    public String name;
    public int type;
    public Vector subClasses;
    public Vector superClasses;
    public Vector disjoint;
    public Vector properties;
    public Vector restrictions;
    
    public static final int CLASS = 1;
    public static final int THING = 2;
    
    public static final int OTHER = -1;
}


